﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CrossBasket.cs" company="">
//   
// </copyright>
// <summary>
//   The cross basket.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using Systemathics.FrameWork;
using Systemathics.Indicators;


namespace Systemathics.Automates
{
    [SetBars(BarType.Seconds, 60)]
    [GUI("Systemathics.Trader", "1.0")]
    [Pattern("Systemathics.Automates.CrossBasket.dll", "1.0")]
    public sealed class CrossBasket : Strategy
    {
        private const int LAG = 0;
        private const double REBALANCE_TRESHOLD = 0.1;
        private readonly Dictionary<Guid, List<double>> EcartType = new Dictionary<Guid, List<double>>();
        private readonly Dictionary<Guid, YIELDVWAP> YIELDs = new Dictionary<Guid, YIELDVWAP>();
        private Decimal Ewmi;
        private int Go;
        private int n;
        private SystemathicsSound s;
        private int SyncCount;

        public override void OnStart()
        {
            // Load Sector - Choose the good basket ony by activating isTradable others are false
            n = Instruments.Count;
            SyncCount = 0;
            Go = 1;
            if (n < 2) return;

            foreach (Instrument i in Instruments.Values)
            {
                i.CustomValue1 = i.CustomValue2 = 0;
                YIELDs[i.Id] = new YIELDVWAP(i, Data.Bar, BarType.Seconds, 60);
                Draw(i, Data.Quote, Axis.Secondary, Axis.Secondary);
            }

            s = new SystemathicsSound();

            //GetHistoricalData(Instruments, DateTime.Today, DateTime.Today,Data.Trade,0,DataSource.TickCaptureDataBase);
            //Log(Time.Now.TimeOfDay.TotalMilliseconds.ToString());
            base.OnStart();
        }
        public override void OnBarClose(Bar b)
        {
            // Only For Tradable Instruments
            if (this[Expo.Working].Bias <= MaxBias)
            {
                Math.DivRem(SyncCount, n, out Go);
                if (Go == 0 && YIELDs[b.Id].Count() > LAG + 1)
                {
                    Ewmi = 0;
                    foreach (Instrument i in Instruments.Values)
                        Ewmi += (1 / (Decimal)n) * YIELDs[i.Id].Last();

                    foreach (Instrument i in Instruments.Values)
                    {
                        var Excess = YIELDs[i.Id].Last() - Ewmi; // if < Activation Level == 0  [-1 0 1]
                        var weight = -(1 / (Decimal)n) * Math.Sign(Excess);
                        var Delta = (int)Math.Round((decimal)CashEquity * weight / (i.Trade.Price * (Decimal)i.StaticData.Currency.ReferencePrice));
                        OrderSide Side = Delta > 0 ? OrderSide.Buy : OrderSide.Sell;
                        i[Expo.Theo].Add(Side, Math.Abs(Delta), i.Trade.Price);

                        if (Math.Abs(i[Expo.Theo].NetExposedNominal) > Math.Abs(i[Expo.Traded].NetExposedNominal * (1 + REBALANCE_TRESHOLD)))
                        {
                            int Gamma = i[Expo.Theo].Balance - i[Expo.Traded].Balance;
                            var condition = (double)(Math.Abs(Excess) * i.Trade.Price) * i.StaticData.Currency.ReferencePrice * i.StaticData.Rules.TickValue * Gamma;
                            if ( condition > i.StaticData.Fees.Execution(Gamma, i.Trade.Price))
                            {
                                if (Gamma < 0) // What's happen when Gamma is huge --> Wave it !
                                    Sell(i.Id, OrderStyle.Market, i.Blotter[QuoteLevel.One].Bid, Math.Abs(Gamma),new OrderExtension(){Tif = TimeInForce.GoodTillCancel});
                                else if (Gamma > 0)
                                    Buy(i.Id, OrderStyle.Market, i.Blotter[QuoteLevel.One].Ask, Gamma, new OrderExtension() { Tif = TimeInForce.GoodTillCancel });
                            }
                            else
                                Log("Not Interesting to Trade");
                        }

                        i[Expo.Theo].Add(Side, -Math.Abs(Delta), i.Trade.Price);
                    }

                    Instruments.Values.ElementAt(0).CustomValue1 = YIELDs[Instruments.Values.ElementAt(0).Id].Last() - Ewmi;
                    Instruments.Values.ElementAt(1).CustomValue1 = YIELDs[Instruments.Values.ElementAt(0).Id].Last();
                }
            }
            else
            {
                foreach (Instrument i in Instruments.Values)
                    foreach (Order o in i.Orders.Values.Where(u => u.isOpen))
                        i.Modify(o.Id, i.Blotter[QuoteLevel.One].Mid);
                // what's happen if no open orders but some legs not traded, so hedge with fut
            }
            SyncCount++;
        }
        public override void OnTrade(Trade t)
        {
            //Log(t.Price.ToString());

            // if (Instruments[t.Id].MarketData.TradeCount > 100)
            // {
            //      Instruments[t.Id].CustomValue2 = YIELDs[t.Id].Last();
            //      Instruments[t.Id].CustomValue1 = YIELDs[t.Id].Last();
            // }
            //Log(t.Price.ToString());
        }
        public override void OnBlotter(Blotter b)
        {
        }
        public override void OnMarketData(MarketData marketdata)
        {
        }
        public override void OnOrder(Order o)
        {
            switch (o.Status)
            {
                case OrderStatus.ACK:
                    s.ACK();
                    break;
                case OrderStatus.ACK_CANCEL:
                    s.ACK_CANCEL();
                    break;
                case OrderStatus.ACK_MODIFY:
                    s.ACK_MODIFY();
                    break;
                case OrderStatus.FILLED:
                    s.FILLED();
                    break;
                case OrderStatus.PARTIALLY_FILLED:
                    s.PARTIALLY_FILLED();
                    break;
                case OrderStatus.REJECT:
                    Instruments[o.InstrumentId].ReSend(o.Id);
                    s.REJECT();
                    break;
                case OrderStatus.REJECT_CANCEL:
                    s.REJECT_CANCEL();
                    break;
                case OrderStatus.REJECT_MODIFY:
                    s.REJECT_MODIFY();

                    // Make something
                    break;
            }
        }
        public override void OnMoneyManagement(MoneyManagement mm)
        {
            switch (mm.Reason)
            {
                case CashManagementTrigger.MaxBiasTriggered:
                    break;
                case CashManagementTrigger.MarginRequirementTriggered:
                    break;
                case CashManagementTrigger.MaxDrawDownTriggered:
                    break;
                case CashManagementTrigger.CashEquityNegative:
                    Log("Strategy Paused -------> CashEquityNegative :" + mm.Amount);
                    isPaused = true;
                    break;
            }
        }
        public override void OnTradeSeries(TradeSeries series)
        {
            Log(Time.Now.TimeOfDay.TotalMilliseconds.ToString());
        }
        public override void OnQuoteSeries(QuoteSeries series)
        {
        }
        public override void OnBarSeries(BarSeries series)
        {
        }
        public override void OnStop()
        {
            base.OnStop();
        }
    }
}